001 /* 002 * Copyright 2005 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.lang; 020 021 import java.beans.Expression; 022 import java.io.Serializable; 023 import java.lang.reflect.Field; 024 import java.lang.reflect.Array; 025 import java.util.ArrayList; 026 import java.util.Arrays; 027 import java.util.Map; 028 029 import net.dpml.util.PropertyResolver; 030 031 /** 032 * A object resolvable from primitive arguments. 033 * 034 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 035 * @version 1.0.1 036 */ 037 public class Construct implements Value, Serializable 038 { 039 /** 040 * Serial version identifier. 041 */ 042 static final long serialVersionUID = 1L; 043 044 /** 045 * Utility operation that consolidates an array of values and supplimentary 046 * arguments to an array of objects. 047 * 048 * @param map a map of keys and values used in symbolic target resolution 049 * @param params the value array 050 * @param args supplimentary arguments 051 * @return the consolidated argument array 052 * @exception Exception if an error occurs in argument resolution 053 */ 054 public static Object[] getArgs( Map map, Value[] params, Object[] args ) throws Exception 055 { 056 ArrayList list = new ArrayList(); 057 for( int i=0; i < params.length; i++ ) 058 { 059 Value value = params[i]; 060 Object object = value.resolve( map ); 061 if( null != object ) 062 { 063 list.add( object ); 064 } 065 } 066 for( int i=0; i < args.length; i++ ) 067 { 068 Object value = args[i]; 069 if( null != value ) 070 { 071 list.add( value ); 072 } 073 } 074 return list.toArray(); 075 } 076 077 private final String m_method; 078 private final String m_target; 079 private final String m_value; 080 private final Value[] m_args; 081 private final boolean m_compound; 082 083 /** 084 * Create a new construct using the default java.lang.String class as the base type. 085 * @param value the construct value 086 */ 087 public Construct( String value ) 088 { 089 this( null, null, value ); 090 } 091 092 /** 093 * Create a new construct using a supplied target defintion. The target argument 094 * may be either a classname or a symbolic reference in the form ${[key]}. If the 095 * argument is symbolic it resolved relative to a context map supplied by the 096 * application resolving construct values. 097 * 098 * @param target a classname or symbolic reference 099 * @param value the construct value 100 */ 101 public Construct( String target, String value ) 102 { 103 this( target, null, value ); 104 } 105 106 /** 107 * Create a new construct using a supplied target defintion. The target argument 108 * may be either a classname or a symbolic reference in the form ${[key]}. If the 109 * argument is symbolic it is resolved relative to a context map supplied by the 110 * application resolving construct values. If the construct value is symbolic 111 * the implementation will attempt to expand the reference relative to a context 112 * map (if supplied) otherwise the implementation will attempt to expand the value 113 * using system properties. 114 * 115 * @param target a classname or symbolic reference 116 * @param method the method to invoke on the target 117 * @param value the construct value 118 */ 119 public Construct( String target, String method, String value ) 120 { 121 m_target = target; 122 m_method = method; 123 m_value = value; 124 m_args = new Value[0]; 125 m_compound = false; 126 } 127 128 /** 129 * Create a new construct using a supplied target defintion. The target argument 130 * may be either a classname or a symbolic reference in the form ${[key]}. If the 131 * argument is symbolic it is resolved relative to a context map supplied by the 132 * application resolving construct values. Instance values resolved from the 133 * supplied Value[] will be used as constructor arguments when resolving the target. 134 * 135 * @param target the construct classname 136 * @param args an array of unresolved parameter values 137 */ 138 public Construct( String target, Value[] args ) 139 { 140 this( target, null, args ); 141 } 142 143 /** 144 * Create a new construct using a supplied target defintion. The target argument 145 * may be either a classname or a symbolic reference in the form ${[key]}. If the 146 * argument is symbolic it is resolved relative to a context map supplied by the 147 * application resolving construct values. Instance values resolved from the 148 * supplied Value[] will be used as method arguments when resolving the target. 149 * 150 * @param target the construct classname 151 * @param method the method to invoke on the target 152 * @param args an array of unresolved parameter values 153 */ 154 public Construct( String target, String method, Value[] args ) 155 { 156 if( null == args ) 157 { 158 m_args = new Value[0]; 159 } 160 else 161 { 162 m_args = args; 163 } 164 m_value = null; 165 m_target = target; 166 m_method = method; 167 m_compound = true; 168 } 169 170 /** 171 * Creation of a new construct using a value directive. 172 * @param directive the value directive 173 */ 174 public Construct( ValueDirective directive ) 175 { 176 m_value = directive.getBaseValue(); 177 m_target = directive.getTargetExpression(); 178 m_method = directive.getMethodName(); 179 m_compound = directive.isCompound(); 180 ValueDirective[] values = directive.getValueDirectives(); 181 int n = values.length; 182 m_args = new Value[ n ]; 183 for( int i=0; i<n; i++ ) 184 { 185 ValueDirective value = values[i]; 186 m_args[i] = new Construct( value ); 187 } 188 } 189 190 /** 191 * Return TRUE if this construct is a compund construct else FALSE. 192 * @return TRUE if this ia a compound construct 193 */ 194 public boolean isCompound() 195 { 196 return m_compound; 197 } 198 199 /** 200 * Return the method name to be applied to the target object. 201 * @return the method name 202 */ 203 public String getMethodName() 204 { 205 return m_method; 206 } 207 208 /** 209 * Return the set of nested values within this value. 210 * @return the nested values array 211 */ 212 public Value[] getValues() 213 { 214 return m_args; 215 } 216 217 /** 218 * Return the classname of the resolved value. 219 * @return the classname 220 */ 221 public String getBaseValue() 222 { 223 return m_value; 224 } 225 226 /** 227 * Return the classname of the resolved value. 228 * @return the classname 229 */ 230 public String getTargetExpression() 231 { 232 return m_target; 233 } 234 235 /** 236 * Resolve an instance from the value using the context classloader. 237 * @return the resolved instance 238 * @exception Exception if an error occurs during value resolution 239 */ 240 public Object resolve() throws Exception 241 { 242 return resolve( null ); 243 } 244 245 /** 246 * Resolve an instance from the value using a supplied map. 247 * @param map the context map 248 * @return the resolved instance 249 * @exception Exception if an error occurs during value resolution 250 */ 251 public Object resolve( Map map ) throws Exception 252 { 253 return resolve( map, false ); 254 } 255 256 /** 257 * Resolve an instance from the value using a supplied isolation policy. 258 * @param isolate the isolation policy 259 * @return the resolved instance 260 * @exception Exception if an error occurs during value resolution 261 */ 262 public Object resolve( boolean isolate ) throws Exception 263 { 264 return resolve( null, isolate ); 265 } 266 267 /** 268 * Resolve an instance from the value using a supplied context map. If any 269 * target expressions in immediate or nested values contain a symbolic 270 * expression the value will be resolved using the supplied map. 271 * 272 * @param map the context map 273 * @param isolate the isolation policy 274 * @return the resolved instance 275 * @exception Exception if error occurs during instance resolution 276 */ 277 public Object resolve( Map map, boolean isolate ) throws Exception 278 { 279 return resolve( null, map, null, isolate ); 280 } 281 282 /** 283 * Resolve an instance from the value using a supplied context map. If any 284 * target expressions in immediate or nested values contain a symbolic 285 * expression the value will be resolved using the supplied map. 286 * 287 * @param classname the default classname 288 * @param map the context map 289 * @param isolate the isolation policy 290 * @return the resolved instance 291 * @exception Exception if error occurs during instance resolution 292 */ 293 public Object resolve( String classname, Map map, boolean isolate ) throws Exception 294 { 295 return resolve( classname, map, null, isolate ); 296 } 297 298 /** 299 * Resolve an instance from the value. 300 * @param map the context map 301 * @param classloader the classloader to use 302 * @param isolate the isolation policy 303 * @return the resolved instance 304 * @exception Exception if an error occurs during value resolution 305 */ 306 private Object resolve( String classname, Map map, ClassLoader classloader, boolean isolate ) throws Exception 307 { 308 ClassLoader loader = resolveClassLoader( classloader ); 309 Object target = getTargetObject( classname, map, loader ); 310 if( isCompound() ) 311 { 312 if( null == target ) 313 { 314 throw new NullPointerException( "target" ); 315 } 316 else 317 { 318 return resolveCompoundExpression( target, map, loader ); 319 } 320 } 321 else 322 { 323 Object value = resolveBaseValue( map ); 324 if( null == target ) 325 { 326 return value; 327 } 328 else 329 { 330 return resolveSimpleExpression( target, map, loader ); 331 } 332 } 333 } 334 335 private Object resolveBaseValue( Map map ) 336 { 337 return expandSymbols( map, m_value ); 338 } 339 340 private Object resolveSimpleExpression( Object target, Map map, ClassLoader classloader ) throws Exception 341 { 342 String method = getMethodName(); 343 Object value = expandSymbols( map, m_value ); 344 boolean isaClass = ( target.getClass() == Class.class ); 345 if( null == method ) 346 { 347 if( isaClass ) 348 { 349 method = "new"; 350 } 351 else 352 { 353 final String error = 354 "Target expression '" 355 + m_target 356 + "' resolving to an instance of the class [" 357 + target.getClass() 358 + "] canot be resolved due to missing method declaration."; 359 throw new ValueException( error ); 360 } 361 } 362 else 363 { 364 if( isaClass && ( null == value ) ) 365 { 366 // check if the method name is a static field 367 Class c = (Class) target; 368 try 369 { 370 Field field = c.getField( method ); 371 return field.get( c ); 372 } 373 catch( NoSuchFieldException e ) 374 { 375 // assume its a method 376 } 377 } 378 } 379 380 if( value == null ) 381 { 382 Expression expression = new Expression( target, method, new Object[0] ); 383 try 384 { 385 return expression.getValue(); 386 } 387 catch( Throwable e ) 388 { 389 final String error = 390 "Internal error while evalating simple expression using:" 391 + "\n target: " 392 + m_target 393 + " (" 394 + target 395 + ")" 396 + "\n method: " 397 + m_method 398 + " (" 399 + method 400 + ")"; 401 throw new ValueException( error, e ); 402 } 403 } 404 else 405 { 406 Expression expression = new Expression( target, method, new Object[]{value} ); 407 try 408 { 409 return expression.getValue(); 410 } 411 catch( Throwable e ) 412 { 413 final String error = 414 "Internal error while evaluating expression using:" 415 + "\n target: " + m_target + " (" + target + ")" 416 + "\n method: " + m_method + " (" + method + ")" 417 + "\n value: " + m_value + " (" + value.getClass().getName() + ")"; 418 throw new ValueException( error, e ); 419 } 420 } 421 } 422 423 private Object resolveCompoundExpression( Object target, Map map, ClassLoader classloader ) throws Exception 424 { 425 Value[] args = getValues(); 426 Object[] instances = getInstanceValues( map, classloader, args ); 427 String method = getMethodName(); 428 boolean isaClass = ( target.getClass() == Class.class ); 429 430 // 431 // check if we are dealing with an array class and if so return and 432 // array created from the array of nested values 433 // 434 435 if( isaClass ) 436 { 437 Class c = (Class) target; 438 if( c.isArray() ) 439 { 440 Class type = c.getComponentType(); 441 if( type.isPrimitive() ) 442 { 443 return buildPrimitiveArray( type, instances ); 444 } 445 else 446 { 447 Object[] result = 448 (Object[]) Array.newInstance( type, instances.length ); 449 for( int i=0; i<instances.length; i++ ) 450 { 451 Object instance = instances[i]; 452 if( type.isAssignableFrom( instance.getClass() ) ) 453 { 454 result[i] = instances[i]; 455 } 456 else 457 { 458 final String error = 459 "Array [" 460 + type.getName() 461 + "] contains an invalid element [" 462 + instance.getClass().getName() 463 + "]."; 464 throw new ValueException( error ); 465 } 466 } 467 return result; 468 } 469 } 470 } 471 472 // otherwise its a regular expression 473 474 if( null == method ) 475 { 476 if( isaClass ) 477 { 478 method = "new"; 479 } 480 else 481 { 482 final String error = 483 "Missing method declaration in a composite value construct." 484 + "\nTarget: " 485 + target 486 + " (" + target.getClass().getName() 487 + ")"; 488 throw new ValueException( error ); 489 } 490 } 491 else 492 { 493 if( isaClass && ( instances.length == 0 ) ) 494 { 495 // check if the method name is a static field 496 Class c = (Class) target; 497 try 498 { 499 Field field = c.getField( method ); 500 return field.get( c ); 501 } 502 catch( NoSuchFieldException e ) 503 { 504 // assume its a method 505 } 506 } 507 } 508 Expression expression = new Expression( target, method, instances ); 509 try 510 { 511 return expression.getValue(); 512 } 513 catch( Throwable e ) 514 { 515 StringBuffer buffer = new StringBuffer(); 516 buffer.append( "Internal error while evaluating compound expression." ); 517 buffer.append( "\n target: " + m_target + " (" + target + ")" ); 518 buffer.append( "\n method: " + m_method + " (" + method + ")" ); 519 for( int i=0; i<instances.length; i++ ) 520 { 521 buffer.append( 522 "\n param " 523 + ( i+1 ) 524 + ": " 525 + instances[i].getClass().getName() 526 ); 527 } 528 String error = buffer.toString(); 529 throw new ValueException( error, e ); 530 } 531 } 532 533 private Object buildPrimitiveArray( Class type, Object[] instances ) throws ValueException 534 { 535 Object result = Array.newInstance( type, instances.length ); 536 if( Integer.TYPE == type ) 537 { 538 return buildIntArray( instances ); 539 } 540 else if( Short.TYPE == type ) 541 { 542 return buildShortArray( instances ); 543 } 544 else if( Long.TYPE == type ) 545 { 546 return buildLongArray( instances ); 547 } 548 else if( Byte.TYPE == type ) 549 { 550 return buildByteArray( instances ); 551 } 552 else if( Double.TYPE == type ) 553 { 554 return buildDoubleArray( instances ); 555 } 556 else if( Float.TYPE == type ) 557 { 558 return buildFloatArray( instances ); 559 } 560 else if( Character.TYPE == type ) 561 { 562 return buildCharacterArray( instances ); 563 } 564 else if( Boolean.TYPE == type ) 565 { 566 return buildBooleanArray( instances ); 567 } 568 else 569 { 570 final String error = 571 "Primitive array class [" 572 + type.getName() 573 + "] is not recognized."; 574 throw new UnsupportedOperationException( error ); 575 } 576 } 577 578 private Object buildIntArray( Object[] instances ) throws ValueException 579 { 580 Object result = Array.newInstance( Integer.TYPE, instances.length ); 581 for( int i=0; i<instances.length; i++ ) 582 { 583 Object instance = instances[i]; 584 if( instance instanceof Integer ) 585 { 586 Integer integer = (Integer) instance; 587 int v = integer.intValue(); 588 Array.setInt( result, i, v ); 589 } 590 else 591 { 592 final String error = 593 "Supplied int array argument class [" 594 + instance.getClass().getName() 595 + "] is not an Integer."; 596 throw new ValueException( error ); 597 } 598 } 599 return result; 600 } 601 602 private Object buildShortArray( Object[] instances ) throws ValueException 603 { 604 Object result = Array.newInstance( Short.TYPE, instances.length ); 605 for( int i=0; i<instances.length; i++ ) 606 { 607 Object instance = instances[i]; 608 if( instance instanceof Short ) 609 { 610 Short primitive = (Short) instance; 611 short v = primitive.shortValue(); 612 Array.setShort( result, i, v ); 613 } 614 else 615 { 616 final String error = 617 "Supplied short array argument class [" 618 + instance.getClass().getName() 619 + "] is not an Short."; 620 throw new ValueException( error ); 621 } 622 } 623 return result; 624 } 625 626 private Object buildLongArray( Object[] instances ) throws ValueException 627 { 628 Object result = Array.newInstance( Long.TYPE, instances.length ); 629 for( int i=0; i<instances.length; i++ ) 630 { 631 Object instance = instances[i]; 632 if( instance instanceof Long ) 633 { 634 Long primitive = (Long) instance; 635 long v = primitive.longValue(); 636 Array.setLong( result, i, v ); 637 } 638 else 639 { 640 final String error = 641 "Supplied long array argument class [" 642 + instance.getClass().getName() 643 + "] is not an instance of Long."; 644 throw new ValueException( error ); 645 } 646 } 647 return result; 648 } 649 650 private Object buildByteArray( Object[] instances ) throws ValueException 651 { 652 Object result = Array.newInstance( Byte.TYPE, instances.length ); 653 for( int i=0; i<instances.length; i++ ) 654 { 655 Object instance = instances[i]; 656 if( instance instanceof Byte ) 657 { 658 Byte primitive = (Byte) instance; 659 byte v = primitive.byteValue(); 660 Array.setByte( result, i, v ); 661 } 662 else 663 { 664 final String error = 665 "Supplied byte array argument class [" 666 + instance.getClass().getName() 667 + "] is not an instance of Byte."; 668 throw new ValueException( error ); 669 } 670 } 671 return result; 672 } 673 674 private Object buildDoubleArray( Object[] instances ) throws ValueException 675 { 676 Object result = Array.newInstance( Double.TYPE, instances.length ); 677 for( int i=0; i<instances.length; i++ ) 678 { 679 Object instance = instances[i]; 680 if( instance instanceof Double ) 681 { 682 Double primitive = (Double) instance; 683 double v = primitive.doubleValue(); 684 Array.setDouble( result, i, v ); 685 } 686 else 687 { 688 final String error = 689 "Supplied double array argument class [" 690 + instance.getClass().getName() 691 + "] is not an instance of Double."; 692 throw new ValueException( error ); 693 } 694 } 695 return result; 696 } 697 698 private Object buildFloatArray( Object[] instances ) throws ValueException 699 { 700 Object result = Array.newInstance( Float.TYPE, instances.length ); 701 for( int i=0; i<instances.length; i++ ) 702 { 703 Object instance = instances[i]; 704 if( instance instanceof Float ) 705 { 706 Float primitive = (Float) instance; 707 float v = primitive.floatValue(); 708 Array.setFloat( result, i, v ); 709 } 710 else 711 { 712 final String error = 713 "Supplied float array argument class [" 714 + instance.getClass().getName() 715 + "] is not an instance of Float."; 716 throw new ValueException( error ); 717 } 718 } 719 return result; 720 } 721 722 private Object buildCharacterArray( Object[] instances ) throws ValueException 723 { 724 Object result = Array.newInstance( Character.TYPE, instances.length ); 725 for( int i=0; i<instances.length; i++ ) 726 { 727 Object instance = instances[i]; 728 if( instance instanceof Character ) 729 { 730 Character primitive = (Character) instance; 731 char v = primitive.charValue(); 732 Array.setChar( result, i, v ); 733 } 734 else 735 { 736 final String error = 737 "Supplied char array argument class [" 738 + instance.getClass().getName() 739 + "] is not an instance of Character."; 740 throw new ValueException( error ); 741 } 742 } 743 return result; 744 } 745 746 private Object buildBooleanArray( Object[] instances ) throws ValueException 747 { 748 Object result = Array.newInstance( Boolean.TYPE, instances.length ); 749 for( int i=0; i<instances.length; i++ ) 750 { 751 Object instance = instances[i]; 752 if( instance instanceof Boolean ) 753 { 754 Boolean primitive = (Boolean) instance; 755 boolean v = primitive.booleanValue(); 756 Array.setBoolean( result, i, v ); 757 } 758 else 759 { 760 final String error = 761 "Supplied boolean array argument class [" 762 + instance.getClass().getName() 763 + "] is not an instance of Boolean."; 764 throw new ValueException( error ); 765 } 766 } 767 return result; 768 } 769 770 private Object[] getInstanceValues( 771 Map map, ClassLoader classloader, Value[] args ) throws Exception 772 { 773 Object[] instances = new Object[ args.length ]; 774 for( int i=0; i < args.length; i++ ) 775 { 776 Value value = args[i]; 777 if( value instanceof Construct ) 778 { 779 Construct construct = (Construct) value; 780 instances[i] = construct.resolve( null, map, classloader, false ); 781 } 782 else 783 { 784 instances[i] = value.resolve( map ); 785 } 786 } 787 return instances; 788 } 789 790 private Object expandSymbols( Map map, String value ) 791 { 792 if( null == value ) 793 { 794 return null; 795 } 796 else 797 { 798 return parseSymbolicValue( map, value ); 799 } 800 } 801 802 private Object parseSymbolicValue( Map map, String value ) 803 { 804 if( null == map ) 805 { 806 return PropertyResolver.resolve( value ); 807 } 808 if( value.startsWith( "${" ) && value.endsWith( "}" ) ) 809 { 810 String pre = value.substring( 2 ); 811 String key = pre.substring( 0, pre.length() -1 ); 812 if( map.containsKey( key ) ) 813 { 814 return map.get( key ); 815 } 816 else 817 { 818 return PropertyResolver.resolve( value ); 819 } 820 } 821 else 822 { 823 return PropertyResolver.resolve( value ); 824 } 825 } 826 827 /** 828 * Return the instance class using the context classloader. 829 * @return the target object or class 830 * @exception ValueException if target related error occurs 831 */ 832 private Object getTargetObject( String classname, Map map, ClassLoader loader ) throws ValueException 833 { 834 if( null == m_target ) 835 { 836 return getTargetObject( map, loader, classname ); 837 } 838 else 839 { 840 return getTargetObject( map, loader, m_target ); 841 } 842 } 843 844 /** 845 * Return the instance class using the context classloader. 846 * @return the target object or class 847 * @exception ValueException if target related error occurs 848 */ 849 private Object getTargetObject( Map map, ClassLoader loader, String target ) throws ValueException 850 { 851 if( null == target ) 852 { 853 return null; 854 } 855 else if( target.startsWith( "${" ) ) 856 { 857 if( null != map ) 858 { 859 String pre = target.substring( 2 ); 860 String key = pre.substring( 0, pre.length() -1 ); 861 if( map.containsKey( key ) ) 862 { 863 return map.get( key ); 864 } 865 else 866 { 867 final String error = 868 "Unresolvable target symbolic expression [" 869 + target 870 + "]."; 871 throw new ValueException( error ); 872 } 873 } 874 else 875 { 876 String resolved = PropertyResolver.resolve( target ); 877 return getTargetObject( map, loader, resolved ); 878 } 879 } 880 else 881 { 882 if( target.endsWith( "[]" ) ) 883 { 884 int n = target.length() - 2; 885 String componentClassname = target.substring( 0, n ); 886 Class componentClass = resolveType( loader, componentClassname ); 887 return Array.newInstance( componentClass, 0 ).getClass(); 888 } 889 else 890 { 891 return resolveClass( loader, target ); 892 } 893 } 894 } 895 896 /** 897 * Return the instance class using the context classloader. 898 * @return the class 899 * @exception ComponentException if the parameter class cannot be resolved 900 */ 901 private Class resolveClass( ClassLoader loader, String classname ) throws ValueException 902 { 903 try 904 { 905 return loader.loadClass( classname ); 906 } 907 catch( final ClassNotFoundException e ) 908 { 909 if( classname.equals( "int" ) ) 910 { 911 return Integer.class; 912 } 913 else if( classname.equals( "short" ) ) 914 { 915 return Short.class; 916 } 917 else if( classname.equals( "long" ) ) 918 { 919 return Long.class; 920 } 921 else if( classname.equals( "byte" ) ) 922 { 923 return Byte.class; 924 } 925 else if( classname.equals( "double" ) ) 926 { 927 return Double.class; 928 } 929 else if( classname.equals( "float" ) ) 930 { 931 return Float.class; 932 } 933 else if( classname.equals( "char" ) ) 934 { 935 return Character.class; 936 } 937 else if( classname.equals( "boolean" ) ) 938 { 939 return Boolean.class; 940 } 941 else 942 { 943 final String error = 944 "Class not found [" 945 + classname 946 + "]."; 947 throw new ValueException( error, e ); 948 } 949 } 950 } 951 952 /** 953 * Return the instance class using the context classloader. 954 * @return the class 955 * @exception ComponentException if the parameter class cannot be resolved 956 */ 957 private Class resolveType( ClassLoader loader, String classname ) throws ValueException 958 { 959 try 960 { 961 return loader.loadClass( classname ); 962 } 963 catch( final ClassNotFoundException e ) 964 { 965 if( classname.equals( "int" ) ) 966 { 967 return Integer.TYPE; 968 } 969 else if( classname.equals( "short" ) ) 970 { 971 return Short.TYPE; 972 } 973 else if( classname.equals( "long" ) ) 974 { 975 return Long.TYPE; 976 } 977 else if( classname.equals( "byte" ) ) 978 { 979 return Byte.TYPE; 980 } 981 else if( classname.equals( "double" ) ) 982 { 983 return Double.TYPE; 984 } 985 else if( classname.equals( "float" ) ) 986 { 987 return Float.TYPE; 988 } 989 else if( classname.equals( "char" ) ) 990 { 991 return Character.TYPE; 992 } 993 else if( classname.equals( "boolean" ) ) 994 { 995 return Boolean.TYPE; 996 } 997 else 998 { 999 final String error = 1000 "Class not found [" 1001 + classname 1002 + "]."; 1003 throw new ValueException( error, e ); 1004 } 1005 } 1006 } 1007 1008 private ClassLoader resolveClassLoader( ClassLoader classloader ) 1009 { 1010 if( null != classloader ) 1011 { 1012 return classloader; 1013 } 1014 else 1015 { 1016 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 1017 if( null == loader ) 1018 { 1019 return Construct.class.getClassLoader(); 1020 } 1021 else 1022 { 1023 return loader; 1024 } 1025 } 1026 } 1027 1028 /** 1029 * Return a string representation of the construct. 1030 * @return the string value 1031 */ 1032 public String toString() 1033 { 1034 if( !m_compound ) 1035 { 1036 return "construct " 1037 + " target: " + m_target 1038 + " method: " + m_method 1039 + " value: " + m_value; 1040 } 1041 else 1042 { 1043 return "construct " 1044 + " target: " + m_target 1045 + " method: " + m_method 1046 + " values: " + m_args.length; 1047 } 1048 } 1049 1050 /** 1051 * Compare this instance with a supplied object for equality. 1052 * @param other the other object 1053 * @return true if the supplied instance is equal to this instance 1054 */ 1055 public boolean equals( Object other ) 1056 { 1057 if( null == other ) 1058 { 1059 return false; 1060 } 1061 if( other instanceof Construct ) 1062 { 1063 Construct construct = (Construct) other; 1064 if( !equals( m_target, construct.m_target ) ) 1065 { 1066 return false; 1067 } 1068 if( m_compound != construct.m_compound ) 1069 { 1070 return false; 1071 } 1072 if( !equals( m_method, construct.m_method ) ) 1073 { 1074 return false; 1075 } 1076 if( m_compound ) 1077 { 1078 return Arrays.equals( m_args, construct.m_args ); 1079 } 1080 else 1081 { 1082 return equals( m_value, construct.m_value ); 1083 } 1084 } 1085 else 1086 { 1087 return false; 1088 } 1089 } 1090 1091 /** 1092 * Compute the instance hashcode value. 1093 * @return the hashcode 1094 */ 1095 public int hashCode() 1096 { 1097 int hash = 0; 1098 if( null != m_target ) 1099 { 1100 hash ^= m_target.hashCode(); 1101 } 1102 if( null != m_method ) 1103 { 1104 hash ^= m_method.hashCode(); 1105 } 1106 if( m_compound ) 1107 { 1108 for( int i=0; i<m_args.length; i++ ) 1109 { 1110 hash ^= m_args[i].hashCode(); 1111 } 1112 } 1113 else 1114 { 1115 if( m_value != null ) 1116 { 1117 hash ^= m_value.hashCode(); 1118 } 1119 } 1120 return hash; 1121 } 1122 1123 private boolean equals( Object a, Object b ) 1124 { 1125 if( null == a ) 1126 { 1127 return ( null == b ); 1128 } 1129 else 1130 { 1131 return a.equals( b ); 1132 } 1133 } 1134 }